#include "mainwindow.h"
#include <QHBoxLayout>
#include <QFileDialog>
#include <QStandardPaths>
#include <QMenuBar>
#include <QStatusBar>
#include <QList>
#include <QMediaMetaData>
#include <QApplication>
#include <QTime>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
    , slider(0)
    , coverLabel(0)
{
    createAction();
    createMenu();
    setupModel();
    setupView();
    setWindowTitle(tr("Like Music"));
    resize(1000,600);
}

MainWindow::~MainWindow()
{

}
void MainWindow::createMenu()
{
    fileMenu = menuBar()->addMenu(tr("file"));
    fileMenu->addAction(openFileAction);
}
void MainWindow::createAction()
{
    //open file
    openFileAction = new QAction(QIcon("open.png"),tr("open"),this);
    openFileAction->setShortcut(tr("Ctrl+O"));
    openFileAction->setStatusTip(tr("open a file"));
    connect(openFileAction,SIGNAL(triggered()),this,SLOT(open()));
}

void MainWindow::setupModel()
{
    model = new PlayListModel();
}

void MainWindow::setupView()
{
    view = new QListView;

    view->setModel(model);
    view->setFrameStyle(QFrame::NoFrame);

    centralWidget = new QWidget();
    setCentralWidget(centralWidget);

    widgetRight = new VideoWidget(this);

    player = new QMediaPlayer(this,QMediaPlayer::StreamPlayback);
    playList = new QMediaPlaylist();

    slider = new QSlider(Qt::Horizontal, this);
    slider->setRange(0, player->duration() / 1000);

    labelDuration = new QLabel(this);

    connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)));

    connect(player, SIGNAL(durationChanged(qint64)), SLOT(durationChanged(qint64)));
    connect(player, SIGNAL(positionChanged(qint64)), SLOT(positionChanged(qint64)));
    connect(player, SIGNAL(metaDataChanged()), SLOT(metaDataChanged()));
    connect(playList, SIGNAL(currentIndexChanged(int)), SLOT(playlistPositionChanged(int)));
    connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
            this, SLOT(statusChanged(QMediaPlayer::MediaStatus)));
    connect(player, SIGNAL(bufferStatusChanged(int)), this, SLOT(bufferingProgress(int)));
    connect(player, SIGNAL(videoAvailableChanged(bool)), this, SLOT(videoAvailableChanged(bool)));
    connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(displayErrorMessage()));

    player->setPlaylist(playList);
    player->setVideoOutput(widgetRight);

    connect(view, SIGNAL(clicked(QModelIndex)), this, SLOT(jump(QModelIndex)));

    PlayerControls *controls = new PlayerControls(this);
    controls->setState(player->state());
    controls->setVolume(player->volume());
    controls->setMuted(controls->isMuted());

    connect(controls, SIGNAL(play()), player, SLOT(play()));
    connect(controls, SIGNAL(pause()), player, SLOT(pause()));
    connect(controls, SIGNAL(stop()), player, SLOT(stop()));
    connect(controls, SIGNAL(next()), playList, SLOT(next()));
    connect(controls, SIGNAL(previous()), this, SLOT(previousClicked()));
    connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int)));
    connect(controls, SIGNAL(changeMuting(bool)), player, SLOT(setMuted(bool)));
    connect(controls, SIGNAL(changeRate(qreal)), player, SLOT(setPlaybackRate(qreal)));

    connect(controls, SIGNAL(stop()), widgetRight, SLOT(update()));

    connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),
            controls, SLOT(setState(QMediaPlayer::State)));
    connect(player, SIGNAL(volumeChanged(int)), controls, SLOT(setVolume(int)));
    connect(player, SIGNAL(mutedChanged(bool)), controls, SLOT(setMuted(bool)));

    coverLabel = new QLabel(this);

    durationLayout = new QHBoxLayout();
    durationLayout->addWidget(slider);
    durationLayout->addWidget(labelDuration);
    durationLayout->addWidget(coverLabel);

    videoHistogram = new HistogramWidget(this);
    videoProbe = new QVideoProbe(this);
    connect(videoProbe, SIGNAL(videoFrameProbed(QVideoFrame)), videoHistogram, SLOT(processFrame(QVideoFrame)));
    videoProbe->setSource(player);

    audioHistogram = new HistogramWidget(this);
    audioProbe = new QAudioProbe(this);
    connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)), audioHistogram, SLOT(processBuffer(QAudioBuffer)));
    audioProbe->setSource(player);

    rightLayout = new QVBoxLayout();
    rightLayout->addWidget(widgetRight,1);
    rightLayout->addLayout(durationLayout);
    rightLayout->addWidget(controls);
    rightLayout->addWidget(audioHistogram);
    rightLayout->addWidget(videoHistogram);
    rightLayout->setSpacing(5);

    mainLayout = new QHBoxLayout(centralWidget);
    mainLayout->addWidget(view);
    mainLayout->addLayout(rightLayout);
    //mainLayout->addWidget(histogram);
    mainLayout->setSpacing(5);
    mainLayout->setStretch(0,1);
    mainLayout->setStretch(1,3);
}

void MainWindow::open()
{
    QFileDialog fileDialog(this);
    fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
    fileDialog.setWindowTitle(tr("Open Files"));
    QStringList supportedMimeTypes = player->supportedMimeTypes();
    if (!supportedMimeTypes.isEmpty()) {
        supportedMimeTypes.append("audio/x-m3u"); // MP3 playlists
        fileDialog.setMimeTypeFilters(supportedMimeTypes);
    }
    fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MoviesLocation).value(0, QDir::homePath()));
    if (fileDialog.exec() == QDialog::Accepted)
        addToPlaylist(fileDialog.selectedUrls());
}
void MainWindow::jump(const QModelIndex &index)
{
    if (index.isValid()) {
        playList->setCurrentIndex(index.row());
        player->setVolume(80);
        player->play();
        //qDebug()<<player->mediaStatus();//QString(player->mediaStatus())
    }
}

static bool isPlaylist(const QUrl &url) // Check for ".m3u" playlists.
{
     if (!url.isLocalFile())
         return false;
     const QFileInfo fileInfo(url.toLocalFile());
     return fileInfo.exists() && !fileInfo.suffix().compare(QLatin1String("m3u"), Qt::CaseInsensitive);
}

void MainWindow::addToPlaylist(const QList<QUrl> urls)
{
    foreach (const QUrl &url, urls) {
        if (isPlaylist(url)){
           playList->load(url);
        }else{
           playList->addMedia(url);
        }
    }
    playList->setCurrentIndex(1);
    model->setPlayList(playList);
}


void MainWindow::durationChanged(qint64 duration)
{
    this->duration = duration/1000;
    slider->setMaximum(duration / 1000);
}

void MainWindow::positionChanged(qint64 progress)
{
    if (!slider->isSliderDown()) {
        slider->setValue(progress / 1000);
    }
    updateDurationInfo(progress / 1000);
}

void MainWindow::metaDataChanged()
{
    if (player->isMetaDataAvailable()) {
        setTrackInfo(QString("%1 - %2")
                .arg(player->metaData(QMediaMetaData::AlbumArtist).toString())
                .arg(player->metaData(QMediaMetaData::Title).toString()));
        if (coverLabel) {
            QUrl url = player->metaData(QMediaMetaData::CoverArtUrlLarge).value<QUrl>();
            coverLabel->setPixmap(!url.isEmpty()
                    ? QPixmap(url.toString())
                    : QPixmap());
        }

    }
}

void MainWindow::previousClicked()
{
    // Go to previous track if we are within the first 5 seconds of playback
    // Otherwise, seek to the beginning.
    if(player->position() <= 5000)
        playList->previous();
    else
        player->setPosition(0);
}

void MainWindow::playlistPositionChanged(int currentItem)
{
    clearHistogram();
    //playlistView->setCurrentIndex(playlistModel->index(currentItem, 0));
}

void MainWindow::seek(int seconds)
{
    player->setPosition(seconds * 1000);
}

void MainWindow::statusChanged(QMediaPlayer::MediaStatus status)
{
    handleCursor(status);

    // handle status message
    switch (status) {
    case QMediaPlayer::UnknownMediaStatus:
    case QMediaPlayer::NoMedia:
    case QMediaPlayer::LoadedMedia:
    case QMediaPlayer::BufferingMedia:
    case QMediaPlayer::BufferedMedia:
        setStatusInfo(QString());
        break;
    case QMediaPlayer::LoadingMedia:
        setStatusInfo(tr("Loading..."));
        break;
    case QMediaPlayer::StalledMedia:
        setStatusInfo(tr("Media Stalled"));
        break;
    case QMediaPlayer::EndOfMedia:
        QApplication::alert(this);
        break;
    case QMediaPlayer::InvalidMedia:
        displayErrorMessage();
        break;
    }
}

void MainWindow::handleCursor(QMediaPlayer::MediaStatus status)
{
#ifndef QT_NO_CURSOR
    if (status == QMediaPlayer::LoadingMedia ||
        status == QMediaPlayer::BufferingMedia ||
        status == QMediaPlayer::StalledMedia)
        setCursor(QCursor(Qt::BusyCursor));
    else
        unsetCursor();
#endif
}

void MainWindow::bufferingProgress(int progress)
{
    setStatusInfo(tr("Buffering %4%").arg(progress));
}

void MainWindow::videoAvailableChanged(bool available)
{
//    if (!available) {
//        disconnect(fullScreenButton, SIGNAL(clicked(bool)),
//                    videoWidget, SLOT(setFullScreen(bool)));
//        disconnect(videoWidget, SIGNAL(fullScreenChanged(bool)),
//                fullScreenButton, SLOT(setChecked(bool)));
//        videoWidget->setFullScreen(false);
//    } else {
//        connect(fullScreenButton, SIGNAL(clicked(bool)),
//                videoWidget, SLOT(setFullScreen(bool)));
//        connect(videoWidget, SIGNAL(fullScreenChanged(bool)),
//                fullScreenButton, SLOT(setChecked(bool)));

//        if (fullScreenButton->isChecked())
//            videoWidget->setFullScreen(true);
//    }

}

void MainWindow::setTrackInfo(const QString &info)
{
    trackInfo = info;
    if (!statusInfo.isEmpty())
        statusBar()->showMessage(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        statusBar()->showMessage(trackInfo);
}

void MainWindow::setStatusInfo(const QString &info)
{

    statusInfo = info;
    if (!statusInfo.isEmpty())
        statusBar()->showMessage(QString("%1 | %2").arg(trackInfo).arg(statusInfo));
    else
        statusBar()->showMessage(trackInfo);

}

void MainWindow::displayErrorMessage()
{
    setStatusInfo(player->errorString());
}

void MainWindow::updateDurationInfo(qint64 currentInfo)
{
    QString tStr;
    if (currentInfo || duration) {
        QTime currentTime((currentInfo/3600)%60, (currentInfo/60)%60, currentInfo%60, (currentInfo*1000)%1000);
        QTime totalTime((duration/3600)%60, (duration/60)%60, duration%60, (duration*1000)%1000);
        QString format = "mm:ss";
        if (duration > 3600)
            format = "hh:mm:ss";
        tStr = currentTime.toString(format) + " / " + totalTime.toString(format);
    }
    labelDuration->setText(tStr);
}

void MainWindow::clearHistogram()
{
    QMetaObject::invokeMethod(videoHistogram, "processFrame", Qt::QueuedConnection, Q_ARG(QVideoFrame, QVideoFrame()));
    QMetaObject::invokeMethod(audioHistogram, "processBuffer", Qt::QueuedConnection, Q_ARG(QAudioBuffer, QAudioBuffer()));
}
